/*
 * Simon-Says
 *
 * This games plays a series of tones/lamp combinations, which the
 * player has to repeat. After each successful game, the series
 * increases in length. ESCAPE exits.
 *
 * Copyright 1994-2003 Dave Dunfield
 * All rights reserved.
 *
 * Permission granted for personal (non-commercial) use only.
 *
 * Compile command: cc simon -fop
 */
#include <stdio.h>
#include <window.h>

#define	LAMPS		9		/* Number of lamps to play */
#define	GAME_PAUSE	1000	/* Delay between games */
#define	LAMP_PAUSE	50		/* Delay between lamp/beeps */
#define	TONE_LENGTH	500		/* Length of beeps (in MS) */
#define	FAIL_TONE1	75		/* Fail beep #1 value */
#define	FAIL_TONE2	50		/* Fail beep #2 value */
#define	PASS_TONE1	1100	/* Pass beep #1 value */
#define	PASS_TONE2	1200	/* Pass beep #2 value */

extern unsigned RAND_SEED;	/* Seed for random number generator */

/*
 * Tone table to map beeps to lamps
 */
static unsigned lamp_beeps[] = {
	200, 250, 300, 350, 400, 450, 500, 550, 600
	};

/*
 * Play the "simon says" game
 */
main()
{
	unsigned i, lamp, length, seed;

	/* Open a window and display the title */
	wopen(0, 0, 80, 24, WSAVE|WCOPEN|NORMAL);
	wcursor_off();
	wgotoxy(32, 0);
	*W_OPEN = REVERSE;
	wputs("  SIMON SAYS  ");
	*W_OPEN = NORMAL;

	/* Draw the playing field */
	wgotoxy(30,  6); xputs("7-----8-----8-----9");
	wgotoxy(30,  7); xputs("|     |     |     |");
	wgotoxy(30,  8); xputs("|     |     |     |");
	wgotoxy(30,  9); xputs("|     |     |     |");
	wgotoxy(30, 10); xputs("4-----5-----5-----6");
	wgotoxy(30, 11); xputs("|     |     |     |");
	wgotoxy(30, 12); xputs("|     |     |     |");
	wgotoxy(30, 13); xputs("|     |     |     |");
	wgotoxy(30, 14); xputs("4-----5-----5-----6");
	wgotoxy(30, 15); xputs("|     |     |     |");
	wgotoxy(30, 16); xputs("|     |     |     |");
	wgotoxy(30, 17); xputs("|     |     |     |");
	wgotoxy(30, 18); xputs("1-----2-----2-----3");

	/* Randomize the random number generator */
	get_time(&i, &lamp, &seed);
	RAND_SEED = (i*3600) + (lamp*60) + seed;

	length = 1;								/* First game is 1 beep */

	for(;;) {
		seed = RAND_SEED;					/* Record position in series */

	retry:
		delay(GAME_PAUSE);
		wgotoxy(0, 1);
		wprintf("Length = %u ", length);
		RAND_SEED = seed;					/* Save so we can reset */

		for(i=0; i < length; ++i) {			/* Play the series */
			light_lamp(lamp = random(LAMPS));
			beep(lamp_beeps[lamp], TONE_LENGTH);
			light_lamp(-1);
			delay(LAMP_PAUSE); }

		light_lamp(-1);
		wgotoxy(60, 1);
		wputs("Your turn.");
		wcleol();

		RAND_SEED = seed;					/* Reset position in series */
		for(i=0; i < length; ++i) {
			if((lamp = get_key()) > LAMPS) {/* Test for exit key */
				wclose();
				return -1; }
			if(random(LAMPS) != lamp) {		/* Does this one match? */
				light_lamp(-1);
				wgotoxy(60, 1);
				wputs("Try again...");
				wcleol();
				for(i=0; i < 2; ++i) {
					beep(FAIL_TONE1, TONE_LENGTH/2);
					beep(FAIL_TONE2, TONE_LENGTH/2); }
				goto retry; }
			light_lamp(lamp);
			beep(lamp_beeps[lamp], TONE_LENGTH);
			light_lamp(-1); }

		wgotoxy(60, 1);
		wputs("You got it!");
		wcleol();
		for(i=0; i < 2; ++i) {			/* We did it! Celebrate */
			beep(PASS_TONE1, TONE_LENGTH/2);
			beep(PASS_TONE2, TONE_LENGTH/2); }
		++length; }
}

/*
 * Light lamp from indicated lamp code (-1 = all lamps off)
 */
light_lamp(int lamp)
{
	int i, x, y;


	for(i=0; i < LAMPS; ++i) {
		x = i % 3;
		y = i / 3;
		if(i == lamp)
			*W_OPEN = REVERSE;
		wgotoxy((x*6)+31, (y*4)+7); wputs("     ");
		wgotoxy((x*6)+31, (y*4)+8);
		wputs("  ");
		wputc(i+'1');
		wputs("  ");
		wgotoxy((x*6)+31, (y*4)+9); wputs("     ");
		*W_OPEN = NORMAL; }
}

/*
 * Get a key. Return 0-LAMPS, or LAMPS+1 for exit
 */
get_key()
{
	int i;
	for(;;) switch(i = toupper(wgetc())) {
		case '1' :
		case '2' :
		case '3' :
		case '4' :
		case '5' :
		case '6' :
		case '7' :
		case '8' :
		case '9' :
			return i - '1';
		case 0x1B :
			return LAMPS+1; }
}

/*
 * Write to window with graphic character translations
 * Use '|' for vertical bar, '-' for horizontal bar,
 * Corners, sides and crosses use corresponding digits
 * from PC numeric keypad.
 */
xputs(char *ptr)
{
	char c;
	for(;;) {
		switch(c = *ptr++) {
			case 0 :	return;
			case '-' :	c = 0xC4;	break;
			case '|' :	c = 0xB3;	break;
			case '1' :	c = 0xC0;	break;
			case '2' :	c = 0xC1;	break;
			case '3' :	c = 0xD9;	break;
			case '4' :	c = 0xC3;	break;
			case '5' :	c = 0xC5;	break;
			case '6' :	c = 0xB4;	break;
			case '7' :	c = 0xDA;	break;
			case '8' :	c = 0xC2;	break;
			case '9' :	c = 0xBF; }
		wputc(c); }
}
